package com.wang;

import com.wang.config.MyConfig;
import com.wang.dao.ComponentDao;
import com.wang.domain.*;
import com.wang.sevice.ComponentService;
import com.wang.web.ComponentController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 启动类，入口
 */
public class App {
    public static void main(String[] args) {
        /**
         * spring context初始化
         * 1.通过类名引入Bean配置
         * 2.通过包名引入Bean配置
         */
        // 1.以配置类的方式引入Bean的配置：@Configuration（@Bean）、@Component、@Controller、@Service、@Repository等
        //  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class, ComponentBean.class, ComponentController.class, ComponentService.class, ComponentDao.class);
        // 2.以basePackage的方式引入Bean的配置
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.wang");

        /**
         * 获取spring bean的方式：
         *  1.通过类型获取
         *  2.通过名称获取
         */
        // 1.以类型的方式获取实例，要求此类型仅有一个实例注入spring，否则报错
        System.out.println(context.getBean(BasicBean.class));
        // 2.以名称的方式获取实例
        System.out.println(context.getBean("wangBean"));

        /**
         * spring中bean默认是单例的，使用@Scope("prototype)注解引入多实例Bean
         */
        // 注入多例Bean
        System.out.println(context.getBean("myPrototypeBean"));
        System.out.println(context.getBean("myPrototypeBean"));

        /**
         * Bean的创建方式
         * 1.Configuration和@Bean注解
         * 2.使用FactoryBean创建
         * 3.@Component、@Controller、@Service、@Repository注解
         */
        // 使用FactoryBean创建Bean
        System.out.println(context.getBean(Runnable.class));
        System.out.println(context.getBean("wlyFactoryBean"));
        // 获取FactoryBean，使用名称获取需要在前面加&符号，源码在org.springframework.beans.factory.BeanFactory类里
        System.out.println(context.getBean(MyFactoryBean.class));
        System.out.println(context.getBean("&wlyFactoryBean"));

        // 测试创建Bean，如果创建Bean的函数中包含参数，参数会从spring容器中获取
        System.out.println(context.getBean("wlyBean"));
        System.out.println(context.getBean(ParamBean.class));

        //获取使用@Component、@Repository、@Service、@Controller注入的Bean，需要在AnnotationConfigApplicationContext中引入具体类或者basePackage
        System.out.println((context.getBean(ComponentBean.class) + "======" + context.isSingleton(context.getBeanNamesForType(ComponentBean.class)[0])));
        System.out.println((context.getBean(ComponentController.class) + "======" + context.isSingleton(context.getBeanNamesForType(ComponentController.class)[0])));
        System.out.println((context.getBean(ComponentService.class) + "======" + context.isSingleton(context.getBeanNamesForType(ComponentService.class)[0])));
        System.out.println((context.getBean(ComponentDao.class) + "======" + context.isSingleton(context.getBeanNamesForType(ComponentDao.class)[0])));
        /**
         *  测试Bean的初始化和销毁，包含3种方式
         */
        // 方式1：实现InitializingBean, DisposableBean接口
        System.out.println(context.getBean(InitDestory1.class));
        // 方式2：在@Bean(init="xxx",destory="xxx")注解上指定（推荐）
        System.out.println(context.getBean(InitDestory2.class));
        // 方式3：使用JSR250的@PostConstruct、@PreDestory注解
        System.out.println(context.getBean(InitDestory3.class));

        /**
         * 测试同类型Bean注入多个
         */
        // 获取此种类型都注入了哪些Bean
        System.out.println(context.getBeansOfType(MultipartBean.class));
        // 同类型注入多个Bean，使用类型获取会报错
//        System.out.println(context.getBean(MultipartBean.class));
        // 可以通过名称获取
        System.out.println(context.getBean("wlyMultipartBean1"));
        System.out.println(context.getBean("wlyMultipartBean2"));

        /**
         * 测试依赖注入
         */
        DependencyInjectBean dependencyInjectBean = context.getBean("wlyDIBean", DependencyInjectBean.class);
        dependencyInjectBean.show();

        /**
         * 测试Bean中使用ApplicationContext
         */
        ApplicationContextBean contextBean = context.getBean(ApplicationContextBean.class);
        contextBean.show();
        ApplicationContextBean2 contextBean2 = context.getBean(ApplicationContextBean2.class);
        contextBean2.show();
        ApplicationContextBean3 contextBean3 = context.getBean(ApplicationContextBean3.class);
        contextBean3.show();

        /**
         * BeanPostProcessor
         */
        User user = context.getBean(User.class);
        user.show();

        /**
         * BeanDefinitionRegistryPostProcessor
         */
        context.getBeansOfType(WlyBeanDefinition.class).values().forEach(System.out::println);
        // 关闭spring容器
        context.close();
    }
}
